package tech.yozo.bamboo.ui.reading;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.RectF;

import androidx.camera.core.ImageProxy;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import nl.siegmann.epublib.domain.Book;
import nl.siegmann.epublib.epub.EpubReader;
import tech.yozo.bamboo.db.DictDbHelper;
import tech.yozo.bamboo.model.OcrEngine;
import tech.yozo.bamboo.model.OcrText;
import tech.yozo.bamboo.model.SelectedText;
import tech.yozo.bamboo.model.TranslateEngine;
import tech.yozo.bamboo.model.TtsEngine;
import tech.yozo.bamboo.model.DictWord;
import tech.yozo.bamboo.utils.MimeType;

public class ReadingViewModel extends ViewModel {
    private final OcrEngine ocr;
    private final TtsEngine tts;
    private final EpubReader epubReader;
    private final MutableLiveData<Book> mBook;
    private final MutableLiveData<Bitmap> mImage;
    private final MutableLiveData<SelectedText> mSelectedText;
    private final MutableLiveData<DictWord> mDictWord;
    private final MutableLiveData<String> mTransText;
    private final Map<Integer, String> mTransMap;
    private ExecutorService executor;
    private DictDbHelper dictDbHelper;
    private OcrText mOcrText;

    public ReadingViewModel() {
        ocr = new OcrEngine();
        tts = new TtsEngine();
        epubReader = new EpubReader();

        mBook = new MutableLiveData<>();
        mImage = new MutableLiveData<>();
        mSelectedText = new MutableLiveData<>();
        mDictWord = new MutableLiveData<>();
        mTransText = new MutableLiveData<>();
        mTransMap = new HashMap<>();
    }

    public void init(Context context) {
        ocr.init(context);
        tts.init(context);

        if (executor == null) {
            executor = Executors.newFixedThreadPool(3);
        }
        if (dictDbHelper == null) {
            dictDbHelper = new DictDbHelper(context);
        }
    }

    @Override
    protected void onCleared() {
        ocr.release();
        tts.release();

        if (dictDbHelper != null) {
            dictDbHelper.close();
        }

        if (executor != null) {
            executor.shutdown();
        }
        super.onCleared();
    }

    public void clearState() {
//        if(mImage.getValue() != null) {
//            mImage.getValue().recycle();
//        }
//        mImage.setValue(null);
//        mTransMap.clear();
        mSelectedText.setValue(null);
        mDictWord.setValue(null);
        mTransText.setValue(null);
    }

    public LiveData<Bitmap> getImage() {
        return mImage;
    }

    public LiveData<Book> getBook() {
        return mBook;
    }

    public LiveData<SelectedText> getSelectedText() {
        return mSelectedText;
    }

    public LiveData<DictWord> getDictWord() {
        return mDictWord;
    }

    public LiveData<String> getTransText() {
        return mTransText;
    }

    public void doRead(InputStream inputStream, String type) {
        try {
            switch (Objects.requireNonNull(type)) {
                case MimeType.MIME_TYPE_PNG:
                case MimeType.MIME_TYPE_JPG:
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    inputStream.close();
                    doOCR(bitmap);
                    break;
                case MimeType.MIME_TYPE_EPUB:
                    Book book = epubReader.readEpub(inputStream);
                    inputStream.close();
                    mBook.setValue(book);
                    break;
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void doOCR(Bitmap bitmap) {
        // TODO Bug 001. Bitmap可能是不可变的，需要创建可变副本才能绘制线框
        if (!bitmap.isMutable()) {
            bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        }

        // 释放旧图片
        Bitmap old = mImage.getValue();
        if (old != null && !old.isRecycled()) {
            old.recycle();
        }

        // 更新图片展示
        mImage.setValue(bitmap);

        executor.submit(() -> {
            // OCR 识别
            mOcrText = ocr.doOCR(mImage.getValue());
            // TODO 为了测试更新图片展示
            mImage.postValue(mImage.getValue());
        });
    }

    public void doOCR(ImageProxy imageProxy) {
        // 旋转图片
        Bitmap bitmap;
        int degree = imageProxy.getImageInfo().getRotationDegrees();
        if (degree != 0) {
            Matrix matrix = new Matrix();
            matrix.postRotate(degree);
            bitmap = Bitmap.createBitmap(imageProxy.toBitmap(), 0, 0, imageProxy.getWidth(), imageProxy.getHeight(), matrix, true);
        } else {
            bitmap = imageProxy.toBitmap();
        }

        doOCR(bitmap);
    }

    public void doSelectText(String text) {
        //TODO 位置根据实际修改
        SelectedText selectedText = new SelectedText();
        selectedText.text = text;
        selectedText.rect = new RectF(100, 300, 800, 600);
        mSelectedText.setValue(selectedText);
    }

    public void doSelectText(float[] dst, Matrix matrix) {
        if (mOcrText == null) {
            return;
        }
        SelectedText selectedText = mOcrText.selectText(dst);
        if (selectedText.rect != null) {
            matrix.mapRect(selectedText.rect, selectedText.rect);
        }
        mSelectedText.setValue(selectedText);
    }

    public void doTranslate(String text) {
        if (mTransMap.containsKey(text.hashCode())) {
            mTransText.setValue(mTransMap.get(text.hashCode()));
            return;
        }

        executor.submit(() -> {
            String result = TranslateEngine.doTranslate(text);

            mTransMap.put(text.hashCode(), result);
            mTransText.postValue(result);
        });
    }

    public void doTTS(String text) {
        tts.speakOut(text);
    }

    public void doDict(String word) {
        executor.submit(() -> {
            DictWord dictWord = dictDbHelper.getDictWord(word);
            mDictWord.postValue(dictWord);
        });
    }
}